package com.jackstraw.jack_base.datasource.common.entity;

import com.jackstraw.jack_base.datasource.common.entity.enums.DataSourceSchemaEnum;
import com.jackstraw.jack_base.datasource.common.entity.enums.DataSourceTypeEnum;
import com.jackstraw.jack_base.util.CollectionUtil;
import com.jackstraw.jack_base.util.ObjectUtil;
import com.jackstraw.jack_base.util.StringUtil;
import com.jackstraw.jack_base.util.entity.BaseEntity;
import com.jackstraw.jack_base.util.entity.DefaultConstants;
import com.jackstraw.jack_base.util.exception.BadConfigException;
import com.jackstraw.jack_base.util.exception.enums.ExceptionEnum;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @param <PE>
 */
@Data
@Slf4j
public class PropertiesTenantEntity<PE extends AbstractPropertiesEntity<PE>>
        extends BaseEntity<PropertiesTenantEntity<PE>> {

    /**
     * 租户名称
     */
    private String tenantName = DefaultConstants.DEFAULT_TENANT_NAME;


    /**
     * 数据源模式
     */
    private DataSourceSchemaEnum dataSourceSchemaEnum = DataSourceSchemaEnum.one;


    /**
     * 单数据源名称 or 多数据源下主数据源名称
     */
    private String mainDataSourceName;

    /**
     * 单数据源配置 or 多数据源下主数据源配置
     */
    private PE propertiesEntity;

    /**
     * 多数据源下其余数据源配置
     * <p>
     * 单数据源模式时，此项为空
     */
    private Map<String, PE> otherPropertiesEntityMap;

    /**
     * 该租户下，所有的数据源配置
     */
    private Map<String, PE> allPropertiesEntityMap;


    /**
     * 校验并解析
     *
     * @param dataSourceTypeEnum 数据源类型
     * @param tenantNameSet      租户集合
     * @param dataSourceNameSet  数据源名称集合
     */
    public void checkAndResolve(DataSourceTypeEnum dataSourceTypeEnum, final Set<String> tenantNameSet, final Set<String> dataSourceNameSet) {

        if (StringUtil.StringUtilsBylang3.isEmpty(this.tenantName)) {
            log.error("数据源类型为[{}]的租户名称为空", dataSourceTypeEnum.name());
            throw new BadConfigException(BadConfigException.bulidErrorCode(ExceptionEnum.COMMON_DATASOURCE, "005")
                    , "数据源类型为:[{}]的租户名称为空", dataSourceTypeEnum.name());
        }
        if (tenantNameSet.contains(this.tenantName)) {
            log.error("数据源类型为[{}]的租户重复定义", dataSourceTypeEnum.name());
            throw new BadConfigException(BadConfigException.bulidErrorCode(ExceptionEnum.COMMON_DATASOURCE, "006")
                    , "数据源类型为[{}]的租户重复定义", dataSourceTypeEnum.name());
        }

        tenantNameSet.add(this.tenantName);

        if (StringUtil.StringUtilsBylang3.isEmpty(this.mainDataSourceName)) {
            log.error("数据源类型为[{}]，租户名称为[{}]的主数据源名称为空", dataSourceTypeEnum.name(), this.tenantName);
            throw new BadConfigException(BadConfigException.bulidErrorCode(ExceptionEnum.COMMON_DATASOURCE, "007")
                    , "数据源类型为[{}]，租户名称为[{}]的主数据源名称为空", dataSourceTypeEnum.name(), this.tenantName);
        }

        dataSourceNameSet.add(mainDataSourceName);

        if (ObjectUtil.ObjectUtilByLang3.isEmpty(this.propertiesEntity)) {
            log.error("数据源类型为:[{}],租户为:[{}]的主配置为空", dataSourceTypeEnum.name(), this.tenantName);
            throw new BadConfigException(BadConfigException.bulidErrorCode(ExceptionEnum.COMMON_DATASOURCE, "008")
                    , "数据源类型为:[{}],租户为:[{}]的主配置为空", dataSourceTypeEnum.name(), this.tenantName);
        }
        this.propertiesEntity.resolve(tenantName,mainDataSourceName);

        //将该租户下主数据源配置添加至该租户下所有数据源配置列表
        this.allPropertiesEntityMap = new HashMap<>();
        this.allPropertiesEntityMap.put(this.mainDataSourceName, this.propertiesEntity);


        if (DataSourceSchemaEnum.more.equals(this.dataSourceSchemaEnum)) {
            //说明是多数据源
            if (CollectionUtil.MapUtil.isEmpty(this.otherPropertiesEntityMap)) {
                //多数据源其余数据源为空
                log.warn("数据源类型为:[{}],租户为:[{}]的的数据源模式为多数据源，多数据源配置不存在", dataSourceTypeEnum.name(), this.tenantName);
            }
            if (CollectionUtil.MapUtil.isNotEmpty(this.otherPropertiesEntityMap)) {
                this.otherPropertiesEntityMap.keySet().stream().forEach(dataSourceName -> {
                    dataSourceNameSet.add(dataSourceName);
                    PE pe = this.otherPropertiesEntityMap.get(dataSourceName);
                    pe.resolve(tenantName, dataSourceName);
                });
                //将该租户下其余数据源配置添加至该租户下所有数据源配置列表
                this.allPropertiesEntityMap.putAll(this.otherPropertiesEntityMap);
            }
        }
    }
}
